
#include "Util.h"

#include "Listener.h"
#include "Framework\Renderer.h"
#include "App.h"
#include "Engine.h"
#include "Sprite.h"


class SunSprite : public Sprite
{
public:
	static	SpriteDrawPool	drawPool;
	static	void	resetDrawPools(){
		drawPool.reset();
	}
	SunSprite(){
	}
	virtual ~SunSprite(){
	}
	static	void			renderVisible(){
		Renderer*	renderer=gApp->getRenderer();
		renderer->setTexture(TMU0, gApp->sunTexture);
		renderer->setBlending(GL_ONE, GL_ONE);
		renderer->setMask(COLOR);
		renderer->apply();
		glBegin(GL_QUADS);
		for(unsigned int i=0;i<drawPool.visibleTop;i++){
			gApp->drawLightQuad(((SunSprite*)drawPool.visibleStack[i])->position,gApp->screenX,gApp->screenY,50.0f);
		}
		glEnd();
	}
	virtual bool	message(const char *msg=null,void*	params=null){
		if(msg=="render"){
			drawPool.push(this);
			//return Sprite::message(msg,params);
		}
		return true;
	}
};

SpriteDrawPool	SunSprite::drawPool;

class ShipSprite : public Sprite
{
public:
	vec3		velocity;
	vec3		thrust;
	float		mobility;
	SpriteTrail	trail;
	int			orbitPlanetID;
	virtual float getRadius(){
		return 5.0f;
	}
	virtual bool allowRaycastGeometry(){ return true; }

	ShipSprite(){
		thrust=vec3(0,10,0);
		mobility=1.0f;
		orbitPlanetID=0;
	}
	virtual bool	message(const char *msg=null,void*	params=null){
		if(msg=="update"){

			float	pitchImpulse=gApp->waveGenerators[0]*0.03f;
			float	yawImpulse=gApp->waveGenerators[1]*0.03f;
			float	rollImpulse=gApp->waveGenerators[(id<<3)&7]*0.03f;
			float	thrustImpulse=1.0f;
			float   grand=gApp->waveGenerators[id&7]*mobility;
			float   grand1=gApp->waveGenerators[(id<<4)&7]*mobility;

			//grand*=5.0;
			//grand1*=5.0;
			vec3 rv=transform.getUpVec();
			if(dot(rv,position)>0.0f){// || dot(rv,velocity)<0.0f
				//Slow down and rotate more if we are heading away from center
				float vd=dot(rv,position)/length(position);
				float ivd=1.0f-vd;
				thrustImpulse*=ivd;
				grand*=1.0f+vd;
				grand1*=1.0f+vd;
			}

			pitchImpulse*=grand;
			yawImpulse*=grand1;
			rollImpulse*=grand;

			mat4 rmat=rotateZXY4(rollImpulse,pitchImpulse,yawImpulse);

			rollImpulse=pitchImpulse=yawImpulse=0.0f;
			quat=quaternion(rmat)*quat;
			quat.normalize();
			quat.getMatrix(transform,vec3(0,0,0));


			velocity = velocity + ((transform * vec4(thrust,0.0f)).xyz()*thrustImpulse);
			velocity *= 0.9f;
			float vl= length(velocity);
			const float maxVel=0.3f;
			if(vl>maxVel)velocity=velocity * maxVel / vl;

			position = position + velocity;

			if(orbitPlanetID){
				Sprite*	planet=findSprite(orbitPlanetID);
				if(planet){
					vec3 dlt=this->position-planet->position;
					float dl=length(dlt);
					//if(dl>300.0f)
					{
						dlt=dlt*30.0f/dl;
						this->position=planet->position+dlt;
					}
				}else orbitPlanetID=0;
			}



			transform.setTranslationVec(position.x,position.y,position.z);
			trail.update(position);

		}else if(msg=="render"){
			trail.markForRendering();
			return Sprite::message(msg,params);
		}else  if(msg=="targetCmd"){
			orbitPlanetID=*(int*)params;
			return Sprite::message(msg,params);
		}else 
			return Sprite::message(msg,params);
		return true;
	}
};

class PlanetSprite : public Sprite{
public:
	virtual	float	getRadius(){return 10.0f;}
	virtual bool allowRaycastGeometry(){ return true; }
	~PlanetSprite(){};
};

SpriteDef*	gShipSpriteDefs[16];
SpriteDef*	gPlanetSpriteDef;

bool buildSprites(Renderer* renderer){

	for(int t=0;t<array_size(gShipSpriteDefs);t++)
		gShipSpriteDefs[t]=new SpriteDef();
	if(!loadSpriteDef("ship01","sslighting.shd",gShipSpriteDefs[0]))
		return false;
	if(!loadSpriteDef("ship02","sslighting.shd",gShipSpriteDefs[1]))
		return false;

	gPlanetSpriteDef=new SpriteDef();
	if(!loadSpriteDef("travellermap.001","lighting.shd",gPlanetSpriteDef))
		return false;
	gPlanetSpriteDef->textures[0]=gApp->rtColor2D;

	ShipSprite*	testShip=new ShipSprite();
	
	testShip->thrust=vec3(0,0,0.0001f);
	testShip->mobility=0.0001f;
	testShip->definition=gShipSpriteDefs[0];
	testShip->position=vec3(0,0,0);
	//testShip->thrust=vec3(0,0,0);
	//testShip->mobility=0.0f;
		
	const float galaxyRad=600.0f;
	int	planetIDs[10];
	for(int t=0;t<10;t++){
		SunSprite* sspr=new SunSprite();
		sspr->position=randomSphericalPosition(0.0f,galaxyRad);


		PlanetSprite* planet=new PlanetSprite();
		planet->definition=gPlanetSpriteDef;
		planet->position=sspr->position+randomSphericalPosition(30.0f,80.0f);
		planetIDs[t]=planet->id;

	}

	for(int t=0;t<200;t++){
		testShip=new ShipSprite();
		testShip->definition=gShipSpriteDefs[1];
		testShip->position=randomSphericalPosition(0.0f,galaxyRad);
		testShip->orbitPlanetID=planetIDs[(int)frrand(0,9.99f)];
	}
	
	return true;
}

class HygWarListener : public Listener
{
public:
	virtual bool	message(const char *msg=null,void*	params=null){
		if(msg=="buildSprites"){
			if(!buildSprites((Renderer*) params))return false;
		}else if(msg=="startRendering"){
			SunSprite::resetDrawPools();
		}else if(msg=="renderSprites"){
			SunSprite::renderVisible();
		}else if(msg=="finishRendering"){
		}
		return true;
	}
	HygWarListener(){
		Listener::listen(this,"buildSprites");
		Listener::listen(this,"startRendering");
		Listener::listen(this,"renderSprites");
		Listener::listen(this,"finishRendering");
	}
};

//HygWarListener	gHygWarListener;